<template>
  <div
    :class="['joystick-base', `${type}-type`]"
    ref="base"
    @mousedown="startDrag"
    @touchstart.prevent="startDrag"
  >
    <div
      :class="['joystick-handle', `${type}-type`]"
      :style="handleStyle"
      ref="handle"
    ></div>
  </div>
</template>

<script>
export default {
  name: 'VirtualJoystick',
  props: {
    radius: { type: Number, default: 75 }, // 摇杆底座半径
    type: { type: String, default: 'move' }, // 摇杆类型：'move' 或 'rotate'
  },
  emits: ['move', 'end'],
  data() {
    return {
      dragging: false,
      offsetX: 0,
      offsetY: 0,
    };
  },
  computed: {
    handleStyle() {
      return {
        left: '50%',
        top: '50%',
        transform: `translate(-50%, -50%) translate(${this.offsetX}px, ${this.offsetY}px)`
      };
    },
  },
  methods: {
    getCenter(e) {
      const base = this.$refs.base;
      const rect = base.getBoundingClientRect();
      let clientX, clientY;
      if (e.touches) {
        clientX = e.touches[0].clientX;
        clientY = e.touches[0].clientY;
      } else {
        clientX = e.clientX;
        clientY = e.clientY;
      }
      return {
        x: clientX - rect.left - rect.width / 2,
        y: clientY - rect.top - rect.height / 2,
      };
    },
    startDrag(e) {
      this.dragging = true;
      document.addEventListener('mousemove', this.onDrag);
      document.addEventListener('mouseup', this.endDrag);
      document.addEventListener('touchmove', this.onDrag, { passive: false });
      document.addEventListener('touchend', this.endDrag);
      this.onDrag(e);
    },
    onDrag(e) {
      if (!this.dragging) return;
      if (e.type && e.type.startsWith('touch')) e.preventDefault();
      const { x, y } = this.getCenter(e);
      const dist = Math.sqrt(x * x + y * y);
      let dx = x, dy = y;
      if (dist > this.radius) {
        dx = (x / dist) * this.radius;
        dy = (y / dist) * this.radius;
      }
      this.offsetX = dx;
      this.offsetY = dy;
      
      // 归一化输出
      this.$emit('move', {
        x: dx / this.radius,
        y: dy / this.radius,
      });
    },
    endDrag() {
      this.dragging = false;
      this.offsetX = 0;
      this.offsetY = 0;
      document.removeEventListener('mousemove', this.onDrag);
      document.removeEventListener('mouseup', this.endDrag);
      document.removeEventListener('touchmove', this.onDrag);
      document.removeEventListener('touchend', this.endDrag);
      this.$emit('end');
    },
  },
};
</script>

<style scoped>
.joystick-base {
  width: 150px;
  height: 150px;
  border-radius: 50%;
  background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.2), rgba(0,0,0,0.4));
  border: 3px solid rgba(255,255,255,0.3);
  position: relative;
  box-shadow: inset 0 0 20px rgba(0,0,0,0.3), 0 0 30px rgba(255,255,255,0.1);
  user-select: none;
  touch-action: none;
}
.joystick-handle {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: radial-gradient(circle at 30% 30%, #fff, #ccc);
  border: 2px solid rgba(255,255,255,0.8);
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  transition: box-shadow 0.1s;
  box-shadow: 0 5px 15px rgba(0,0,0,0.3), inset 0 2px 5px rgba(255,255,255,0.5);
  cursor: pointer;
}
.joystick-handle:active {
  background: radial-gradient(circle at 30% 30%, #2ed573, #17a2b8);
  box-shadow: 0 8px 20px rgba(46,213,115,0.4), inset 0 2px 5px rgba(255,255,255,0.7);
}

/* 移动端480px以下优化 */
@media (max-width: 480px) {
  .joystick-base {
    width: 130px;
    height: 130px;
    border-width: 2px;
  }
  
  .joystick-handle {
    width: 36px;
    height: 36px;
    border-width: 1.5px;
  }
  
  /* 移动控制 - 更大 */
  .joystick-base.move-type {
    width: 160px;
    height: 160px;
    border-width: 3px;
  }
  
  .joystick-handle.move-type {
    width: 60px;
    height: 60px;
    border-width: 2px;
  }
  
  /* 旋转控制 - 更小 */
  .joystick-base.rotate-type {
    width: 75px;
    height: 75px;
    border-width: 2px;
  }
  
  .joystick-handle.rotate-type {
    width: 25px;
    height: 25px;
    border-width: 1.5px;
  }
}
</style> 